import { invoke } from '@tauri-apps/api/core';
import { listen, emit } from '@tauri-apps/api/event';
import { getCurrentWindow } from '@tauri-apps/api/window';
import { LogicalSize, LogicalPosition } from '@tauri-apps/api/dpi';
import { open, save } from '@tauri-apps/plugin-dialog';
import {
  sendNotification,
  isPermissionGranted,
  requestPermission,
} from '@tauri-apps/plugin-notification';
import { register, unregister } from '@tauri-apps/plugin-global-shortcut';
// Type definitions
interface NotificationOptions {
  title: string;
  body?: string;
  icon?: string;
}

interface FileDialogOptions {
  title?: string;
  filters?: Array<{ name: string; extensions: string[] }>;
  defaultPath?: string;
}

interface SaveDialogOptions extends FileDialogOptions {
  defaultPath?: string;
}

/**
 * Tauri API wrapper with error handling and type safety
 */
export class TauriAPI {
  private static instance: TauriAPI;

  private constructor() {}

  public static getInstance(): TauriAPI {
    if (!TauriAPI.instance) {
      TauriAPI.instance = new TauriAPI();
    }
    return TauriAPI.instance;
  }

  /**
   * Invoke a Tauri command with error handling
   */
  async invoke<T = any>(command: string, args?: any): Promise<T> {
    try {
      return await invoke<T>(command, args);
    } catch (error) {
      console.error(`Failed to invoke command "${command}":`, error);
      throw error;
    }
  }

  /**
   * Listen to Tauri events
   */
  async listen<T = any>(event: string, callback: (payload: T) => void) {
    try {
      return await listen<T>(event, event => {
        callback(event.payload);
      });
    } catch (error) {
      console.error(`Failed to listen to event "${event}":`, error);
      throw error;
    }
  }

  /**
   * Emit a Tauri event
   */
  async emit(event: string, payload?: any): Promise<void> {
    try {
      await emit(event, payload);
    } catch (error) {
      console.error(`Failed to emit event "${event}":`, error);
      throw error;
    }
  }

  /**
   * Window management
   */
  window = {
    getCurrent: () => getCurrentWindow(),

    show: async () => {
      const window = getCurrentWindow();
      await window.show();
      await window.setFocus();
    },

    hide: async () => {
      const window = getCurrentWindow();
      await window.hide();
    },

    minimize: async () => {
      const window = getCurrentWindow();
      await window.minimize();
    },

    maximize: async () => {
      const window = getCurrentWindow();
      await window.maximize();
    },

    unmaximize: async () => {
      const window = getCurrentWindow();
      await window.unmaximize();
    },

    close: async () => {
      const window = getCurrentWindow();
      await window.close();
    },

    setAlwaysOnTop: async (alwaysOnTop: boolean) => {
      const window = getCurrentWindow();
      await window.setAlwaysOnTop(alwaysOnTop);
    },

    setTitle: async (title: string) => {
      const window = getCurrentWindow();
      await window.setTitle(title);
    },

    center: async () => {
      const window = getCurrentWindow();
      await window.center();
    },

    setSize: async (width: number, height: number) => {
      const window = getCurrentWindow();
      await window.setSize(new LogicalSize(width, height));
    },

    setPosition: async (x: number, y: number) => {
      const window = getCurrentWindow();
      await window.setPosition(new LogicalPosition(x, y));
    },

    isMaximized: async () => {
      const window = getCurrentWindow();
      return await window.isMaximized();
    },

    isMinimized: async () => {
      const window = getCurrentWindow();
      return await window.isMinimized();
    },

    isVisible: async () => {
      const window = getCurrentWindow();
      return await window.isVisible();
    },

    isFocused: async () => {
      const window = getCurrentWindow();
      return await window.isFocused();
    },
  };

  /**
   * File system operations
   */
  fs = {
    openFile: async (options?: FileDialogOptions) => {
      try {
        return await open({
          multiple: false,
          directory: false,
          ...options,
        });
      } catch (error) {
        console.error('Failed to open file dialog:', error);
        throw error;
      }
    },

    openFiles: async (options?: FileDialogOptions) => {
      try {
        return await open({
          multiple: true,
          directory: false,
          ...options,
        });
      } catch (error) {
        console.error('Failed to open files dialog:', error);
        throw error;
      }
    },

    openDirectory: async (options?: FileDialogOptions) => {
      try {
        return await open({
          multiple: false,
          directory: true,
          ...options,
        });
      } catch (error) {
        console.error('Failed to open directory dialog:', error);
        throw error;
      }
    },

    saveFile: async (options?: SaveDialogOptions) => {
      try {
        return await save(options);
      } catch (error) {
        console.error('Failed to open save dialog:', error);
        throw error;
      }
    },
  };

  /**
   * Notification system
   */
  notifications = {
    isPermissionGranted: async () => {
      try {
        return await isPermissionGranted();
      } catch (error) {
        console.error('Failed to check notification permission:', error);
        return false;
      }
    },

    requestPermission: async () => {
      try {
        return await requestPermission();
      } catch (error) {
        console.error('Failed to request notification permission:', error);
        return 'denied';
      }
    },

    send: async (options: NotificationOptions) => {
      try {
        const hasPermission = await this.notifications.isPermissionGranted();
        if (!hasPermission) {
          const permission = await this.notifications.requestPermission();
          if (permission !== 'granted') {
            throw new Error('Notification permission denied');
          }
        }

        await sendNotification({
          title: options.title,
          body: options.body,
          icon: options.icon,
        });
      } catch (error) {
        console.error('Failed to send notification:', error);
        throw error;
      }
    },
  };

  /**
   * Global shortcuts
   */
  shortcuts = {
    register: async (shortcut: string, callback: () => void) => {
      try {
        await register(shortcut, callback);
      } catch (error) {
        console.error(`Failed to register shortcut "${shortcut}":`, error);
        throw error;
      }
    },

    unregister: async (shortcut: string) => {
      try {
        await unregister(shortcut);
      } catch (error) {
        console.error(`Failed to unregister shortcut "${shortcut}":`, error);
        throw error;
      }
    },

    unregisterAll: async () => {
      try {
        await unregister('all');
      } catch (error) {
        console.error('Failed to unregister all shortcuts:', error);
        throw error;
      }
    },
  };

  /**
   * App information and utilities
   */
  app = {
    getName: () => this.invoke<string>('get_app_name'),
    getVersion: () => this.invoke<string>('get_app_version'),
    quit: () => this.invoke('quit_app'),
    restart: () => this.invoke('restart_app'),
    getConfig: () => this.invoke('get_app_config'),
    setConfig: (config: any) => this.invoke('set_app_config', { config }),
  };
}

// Export singleton instance
export const tauri = TauriAPI.getInstance();

// Export convenience functions
export const {
  invoke: tauriInvoke,
  listen: tauriListen,
  emit: tauriEmit,
  window: tauriWindow,
  fs: tauriFs,
  notifications: tauriNotifications,
  shortcuts: tauriShortcuts,
  app: tauriApp,
} = tauri;

// Export default instance
export default tauri;
